package com.yangjie.autotest.hpsa.component;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.inject.Inject;
import javax.inject.Named;

import org.springframework.beans.factory.annotation.Qualifier;

import com.yangjie.autotest.context.ContextIF;
import com.yangjie.autotest.context.GlobalContextProperty;
import com.yangjie.autotest.exception.ValidateFailedException;
import com.yangjie.autotest.hpsa.HPSAService;
import com.yangjie.autotest.hpsa.context.HPSAContextProperty;
import com.yangjie.autotest.hpsa.domain.AuditMessage;
import com.yangjie.autotest.hpsa.domain.AuditMessageParam;
import com.yangjie.autotest.hpsa.domain.BaseOrder;
import com.yangjie.autotest.hpsa.domain.BaseSubOrder;
import com.yangjie.autotest.hpsa.domain.HisParentOrder;
import com.yangjie.autotest.hpsa.domain.ParentOrder;
import com.yangjie.autotest.hpsa.domain.ProvisionFile;
import com.yangjie.autotest.testcase.xml.Param;
import com.yangjie.autotest.testcase.xml.Params;
import com.yangjie.autotest.testcase.xml.TestCases;
import com.yangjie.autotest.util.ReflectionUtil;
import com.yangjie.autotest.util.TestCaseUtils;
import com.yangjie.log.LoggerIF;

@Named("hpsaComp")
public class HPSAValidator {
	@Inject
	HPSAService hpsaService = null;

	@Inject
	private LoggerIF logger = null;
	
	@Inject
	@Qualifier("orderValueConvertPros") 
	private Properties orderValueConvertPros = null;

	private Map<String, String> expectedToMap(String expected) {
		Map<String, String> retval = new HashMap<String, String>();
		String[] kvs = expected.split(",");
		for (String kv : kvs) {
			String[] tmp = kv.trim().split("=");
			retval.put(tmp[0].trim(), tmp[1].trim());
		}
		return retval;
	}
	
	
	public boolean actionExpected(String expected, String actual) {
		logger.debug("Validate auditMessage action:expected=" + expected + ";actual:" + actual);
		if(actual.equals("FTP_Provision") && expected.equalsIgnoreCase(actual)) {
			return true;
		}
		if(expected.equalsIgnoreCase(actual) || expected.equalsIgnoreCase(orderValueConvertPros.getProperty("action." + actual))) {
			return true;
		}
		return false;
	}
	
	
//	public boolean actionExpected(String expected, String actual) {
//		if (actual.equals("2001")) {
//			if (expected.equals("2001") || expected.equalsIgnoreCase("2G Query Subscriber")) {
//				return true;
//			}
//		} else if (actual.equals("1001")) {
//			if (expected.equals("1001") || expected.equalsIgnoreCase("Delete Subscriber")) {
//				return true;
//			}
//		} else if (actual.equals("1002")) {
//			if (expected.equals("1002") || expected.equalsIgnoreCase("Modify Subscriber")) {
//				return true;
//			}
//		} else if (actual.equals("1004")) {
//			if (expected.equals("1004") || expected.equalsIgnoreCase("Create Subscriber")) {
//				return true;
//			}
//		} else if (actual.equals("1006")) {
//			if (expected.equals("1006") || expected.equalsIgnoreCase("Suspend Subscriber")) {
//				return true;
//			}
//		} else if (actual.equals("1007")) {
//			if (expected.equals("1007") || expected.equalsIgnoreCase("Resume Subscriber")) {
//				return true;
//			}
//		} else if (actual.equals("1008")) {
//			if (expected.equals("1008") || expected.equalsIgnoreCase("Change MSISDN")) {
//				return true;
//			}
//		} else if (actual.equals("1009")) {
//			if (expected.equals("1009") || expected.equalsIgnoreCase("Change IMSI")) {
//				return true;
//			}
//		} else if (actual.equals("4001")) {
//			if (expected.equals("4001") || expected.equalsIgnoreCase("Delete(AUC)")) {
//				return true;
//			}
//		} else if (actual.equals("4002")) {
//			if (expected.equals("4002") || expected.equalsIgnoreCase("Delete(SUB+AUC)")) {
//				return true;
//			}
//		} else if (actual.equals("FTP_Provision")) {
//			if (expected.equals("FTP_Provision")) {
//				return true;
//			}
//		}
//
//		return false;
//	}

	public boolean statusExpected(String expected, String actual) {
		logger.debug("Validate auditMessage status:expected=" + expected + ";actual:" + actual);
		return expected.equalsIgnoreCase(actual);
	}

	public boolean msisdnExpected(String expected, String actual) {
		if (expected.length() == 8) {
			expected = "852" + expected;
		}
		logger.debug("Validate auditMessage MSISDN:expected=" + expected + ";actual:" + actual);
		return expected.equalsIgnoreCase(actual);
	}

	public boolean imsiExpected(String expected, String actual) {
		if (expected.length() == 10) {
			expected = "45404" + expected;
		}
		logger.debug("Validate auditMessage IMSI:expected=" + expected + ";actual:" + actual);
		return expected.equalsIgnoreCase(actual);
	}

	private boolean paramExpected(AuditMessage auditMessage, String paramName, String paramValue) {
		logger.debug("Begin Validate auditMessage PARAM: name=" + paramName + ";expected=" + paramValue);
		List<AuditMessageParam> params = auditMessage.getParams();
		for(AuditMessageParam param: params) {
			logger.debug("Param in auditmessage:" + param.getName() + "value:" + param.getValue());
			if(paramName.toUpperCase().contains(param.getName().toUpperCase())) {
				logger.debug("Validate auditMessage PARAM:expected=" + paramValue + ";actual:" + param.getValue());
				if(param != null && param.getValue() != null) { 
					if(param.getValue().toUpperCase().contains(paramValue.toUpperCase().trim())) {
						return true;
					}
				}
			}
		}
		return false;
	}
	
	public boolean auditMessageExpected(ContextIF context, AuditMessage auditMessage, Params params) {
		TestCases testCases = (TestCases) context.getProperty(GlobalContextProperty.TESTCASES);
		for(Param param: params.getParam()) {
			String expectValue = TestCaseUtils.fillVariable(param.getValue(), testCases.getVariables());
			if("Message".equalsIgnoreCase(param.getName())) {
				if(!auditMessageExpected(auditMessage, expectValue)) {
					return false;
				}
			} else if(param.getName().toUpperCase().startsWith("PARAM_")){
				if(!paramExpected(auditMessage, param.getName(), expectValue)) {
					return false;
				}
			}
		}
		return true;
	}
	
	public boolean auditMessageExpected(AuditMessage auditMessage, String expected) {
		logger.debug("Begin Validate auditmessage[:" + auditMessage + "];expected:" + expected);
		Map<String, String> expectedValue = expectedToMap(expected);
		for (String key : expectedValue.keySet()) {			
			String value = expectedValue.get(key);
			if ("action".equalsIgnoreCase(key)) {
				if (!actionExpected(value, auditMessage.getEVENT_TYPE())) {
					return false;
				}
			} else if ("status".equalsIgnoreCase(key)) {
				if (!statusExpected(value, auditMessage.getWORKFLOW_STATE())) {
					return false;
				}
			} else if ("msisdn".equalsIgnoreCase(key)) {
				if (!msisdnExpected(value, auditMessage.getIDENTIFIER())) {
					return false;
				}
			} else if ("imsi".equalsIgnoreCase(key)) {
				if (!imsiExpected(value, auditMessage.getWORKFLOW_TYPE())) {
					return false;
				}
			} else if ("ne".equalsIgnoreCase(key)) {
				logger.debug("Validate auditMessage NE:expected=" + value + ";actual:" + auditMessage.getSTEP_NAME());
				if (!value.equalsIgnoreCase(auditMessage.getSTEP_NAME())) {
					return false;
				}
			}
		}
		return true;
	}

	public String objectListToString(List objects) {
		if(objects == null) {
			return "NONE";
		}
		StringBuffer sb = new StringBuffer();
		for (int i = 0; i < objects.size(); i++) {
			sb.append("[").append(objects.get(i).toString()).append("]");
		}
		return sb.toString();
	}

	
	private int getTimeout(Params params) {
		try {
			for (Param param : params.getParam()) {
				if (param.getName().equalsIgnoreCase("timeout")) {
					return Integer.parseInt(param.getValue());
				}
			}
			return 300;
		} catch (Exception e) {
			return 300;
		}
	}
	
	
	public void checkAuditMessage(ContextIF context, Params params) throws ValidateFailedException {

		int waitTime = 0;
		int timeout = getTimeout(params);
		int timeoutInt = timeout * 1000;
		List<AuditMessage> newAuditMessage = null;
		while (waitTime < timeoutInt) {
			newAuditMessage = hpsaService.getNewAuditMessage((Integer) context.getProperty(HPSAContextProperty.MAX_AUDIT_ID_BEFORE_TEST_CASE));
			if (newAuditMessage.size() != 0) {
				for (AuditMessage auditMessage : newAuditMessage) {
					if (auditMessageExpected(context, auditMessage, params)) {
						return;
					}
				}
			}
			waitTime += 10000;
			try {
				Thread.sleep(10000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				throw new ValidateFailedException(e.getMessage());
			}

		}
		if (newAuditMessage == null) {
			throw new ValidateFailedException("No AuditMessage found.");
		}
		logger.debug("AuditMessages:" + objectListToString(newAuditMessage));
		throw new ValidateFailedException("Validte AuditMessage failed. Expected:" + params + "; Actual:" + objectListToString(newAuditMessage));
	}
	
	/*
	private void checkAuditMessage(ContextIF context, String expected, String timeout) throws ValidateFailedException {

		TestCases testCases = (TestCases) context.getProperty(GlobalContextProperty.TESTCASES);
		expected = TestCaseUtils.fillVariable(expected, testCases.getVariables());
		int waitTime = 0;
		int timeoutInt = Integer.parseInt(timeout) * 1000;
		List<AuditMessage> newAuditMessage = null;
		while (waitTime < timeoutInt) {
			newAuditMessage = hpsaService.getNewAuditMessage((Integer) context.getProperty(HPSAContextProperty.MAX_AUDIT_ID_BEFORE_TEST_CASE));
			if (newAuditMessage.size() != 0) {
				for (AuditMessage auditMessage : newAuditMessage) {
					if (auditMessageExpected(auditMessage, expected)) {
						return;
					}
				}
			}
			waitTime += 10000;
			try {
				Thread.sleep(10000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				throw new ValidateFailedException(e.getMessage());
			}

		}
		if (newAuditMessage == null) {
			throw new ValidateFailedException("No AuditMessage found.");
		}
		logger.debug("AuditMessages:" + objectListToString(newAuditMessage));
		throw new ValidateFailedException("Validte AuditMessage failed. Expected:" + expected + "; Actual:" + objectListToString(newAuditMessage));

	}*/

	/*
	public void checkAuditMessage(ContextIF context, String expected) throws ValidateFailedException {
		checkAuditMessage(context, expected, "120");
	}*/

//	public String convertPsstatus(String psstatus) {
//		if("success".equalsIgnoreCase(psstatus)) {
//			return "6";
//		} else if("halt".equalsIgnoreCase(psstatus)) {
//			return "-3";
//		} else if("failure".equalsIgnoreCase(psstatus)) {
//			return "-1";
//		} else if("hold".equalsIgnoreCase(psstatus)) {
//			return "21";
//		} else if("manualretry".equalsIgnoreCase(psstatus)) {
//			return "20";
//		} else if("processing".equalsIgnoreCase(psstatus)) {
//			return "1";
//		} else if("initialize".equalsIgnoreCase(psstatus)) {
//			return "0";
//		} else if("partialsuccess".equalsIgnoreCase(psstatus)) {
//			return "10";
//		}
//		return psstatus;
//	}
	
	public String convertPsstatus(String psstatus) {
		if(orderValueConvertPros == null) {
			return psstatus;
		}
		return orderValueConvertPros.getProperty("psstatus." + psstatus, psstatus);
	}
	
	
	public boolean fileNameMatch(String expectFileName, String actualValue) {
		Pattern p = Pattern.compile(expectFileName.replaceAll("\\*", "\\\\w*"));
		Matcher m = p.matcher(actualValue);
		return m.matches();
	}
	
	
	private boolean allOrderAttributeMatch(Object obj, Map<String, String> expectedMap) throws Exception{
		for(String key: expectedMap.keySet()) {
			String actualValue = "";
			Object value = ReflectionUtil.getProperty(obj, key);
			
			if(value != null) {
				actualValue = value.toString();
			} else {
				if(key.equalsIgnoreCase("filename")) {
					ProvisionFile provisionFile = ((BaseOrder)obj).getProvisionFile();
					if(provisionFile != null) {
						actualValue = provisionFile.getFILENAME();
					} else {
						actualValue = "";
					}
				}
			}
			
			
			
			String expectedValue = expectedMap.get(key);
			if(key.equalsIgnoreCase("psstatus")) {
				expectedValue = convertPsstatus(expectedValue);
			}
			if(actualValue == null) {
				actualValue = "";
			}
			if(expectedValue == null) {
				expectedValue = "";
			}
			logger.debug("Validate order:key=" + key + ";expectedValue=" + expectedValue + "; actualValue=" + actualValue);
			if(key.equalsIgnoreCase("filename") && expectedValue.contains("*")) {
				if(!fileNameMatch(expectedValue, actualValue)) {
					return false;
				}
			} else {
				if(!expectedValue.equalsIgnoreCase(actualValue)) {
					return false;
				}
			}
		}
		logger.debug("allOrderAttributeMatch=true");
		return true;
	}
	
	
	private String getParamValue(Params params, String name) {
		for(Param param:params.getParam()) {
			if(param.getName().equalsIgnoreCase(name)) {
				return param.getValue();
			}
		}
		return null;
	}
	
	private boolean subOrderMatched(BaseOrder order, Map<String, String> expectedMap) throws Exception{
		for(BaseSubOrder subOrder: order.getSubOrders()) {
			if(allOrderAttributeMatch(subOrder, expectedMap)) {
				return true;
			}
		}
		
		return false;
	}
	
	private boolean orderMatched(List<BaseOrder> orders, Param param)  throws Exception {
		Map<String, String> expectedMap = expectedToMap(param.getValue());
		for(BaseOrder order: orders) {
			if(param.getName().equalsIgnoreCase("suborder")) {
				logger.debug("Begin validate suborder...");
				if(subOrderMatched(order, expectedMap)) {
					return true;
				}
			} else if(param.getName().equalsIgnoreCase("parentorder")) {
				logger.debug("Begin validate parentorder...");
				if(allOrderAttributeMatch(order, expectedMap)) {
					return true;
				}
			}
		}
		logger.debug("not matched order:" + param.toString());
		return false;
	}
	
	
	public boolean allOrdersMatched(List<BaseOrder> orders, Params params) throws Exception {
		for(Param param: params.getParam()) {
			if(!orderMatched(orders, param)) {
				return false;
			}
		}
		return true;
	}
	
	public void checkOrder(ContextIF context, Params params) throws ValidateFailedException {
		List<ParentOrder> orderList = null;
		List<HisParentOrder> hisOrderList = null;
		List<BaseOrder> baseOrderList = null;
		int waitTime = 0;
		int timeoutInt = getTimeout(params) * 1000;
//		String expected = param.getValue();
		
		while (waitTime < timeoutInt) {
			try {
				orderList = hpsaService.getNewParentORder((Integer) context.getProperty(HPSAContextProperty.MAX_PS_ID_BEFORE_TEST_CASE));

				logger.debug("ParentOrders:" + objectListToString(orderList));
				hisOrderList = hpsaService.getNewHisParentORder((Integer) context.getProperty(HPSAContextProperty.MAX_PS_ID_BEFORE_TEST_CASE));

				baseOrderList = new LinkedList<BaseOrder>();
				baseOrderList.addAll(orderList);
				baseOrderList.addAll(hisOrderList);
				if(allOrdersMatched(baseOrderList, params)) {
					return;
				}
				logger.debug("HisParentOrders:" + objectListToString(hisOrderList));
				waitTime += 10000;
				try {
					Thread.sleep(10000);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
					throw new ValidateFailedException(e.getMessage());
				}
				
			} catch (Exception e) {
				e.printStackTrace();
				throw new ValidateFailedException("Validate Order failed." +  "; Actual:" + objectListToString(orderList));
			}
		}
		throw new ValidateFailedException("Validate Order failed. Expected:" + "; Actual:" + objectListToString(orderList) + objectListToString(hisOrderList));
	}

}
